<template>
  <div class="el-transfer">
    <TreeTransferBlock
      ref="from"
      :title="titleLeft"
      :showFilter="showFilter"
      :showAllCheck="showAllCheck"
      v-on:listenCheckedInfoEvent="bindLeftCheckedInfoEvent"
      v-on:listenHalfCheckedInfoEvent="bindLeftHalfCheckedInfoEvent"
      v-bind:check_info="checkedData_left"
      :disabled="transferDisabled"
      :treeInfo="transferData_left"
      :lazy="lazy"
      :lazyFn="loadNode"
    ></TreeTransferBlock>
    <div class="el-transfer__buttons">
      <el-button
        type="default"
        class="el-transfer__button"
        @click.native="addToLeft"
        :disabled="checkedData_right.length === 0 || transferDisabled"
      >
        <i class="el-icon-arrow-left"></i>
      </el-button>
      <el-button
        type="default"
        class="el-transfer__button"
        @click.native="addToRight"
        :disabled="checkedData_left.length === 0 || transferDisabled"
      >
        <i class="el-icon-arrow-right"></i>
      </el-button>
    </div>

    <TreeTransferBlock
      :title="titleRight"
      :showFilter="showFilter"
      :showAllCheck="showAllCheck"
      v-on:listenCheckedInfoEvent="bindRightCheckedInfoEvent"
      v-on:listenHalfCheckedInfoEvent="bindRightHalfCheckedInfoEvent"
      :treeInfo="transferData_right"
      :disabled="transferDisabled"
      v-bind:check_info="checkedData_right"
    >
    </TreeTransferBlock>
  </div>
</template>

<script>
import _ from 'lodash'
import TreeTransferBlock from './TreeTransferBlock' //引入child组件
import { getProvince, getCity, getDistrict } from '@/api/common'
export default {
  components: {
    TreeTransferBlock,
  },
  props: {
    //左侧树列表框名称
    titleLeft: {
      type: String,
    },
    //右侧树列表框名称
    titleRight: {
      type: String,
    },
    //左侧树列表
    data_left: {
      type: Array,
      default: () => [],
    },
    //右侧树列表
    data_right: {
      type: Array,
      default: () => [],
    },
    //是否显示查询筛选框
    showFilter: {
      type: Boolean,
    },
    //是否显示全选按钮
    showAllCheck: {
      type: Boolean,
    },
    disabled: {
      type: Boolean,
    },
    lazy: {
      type: Boolean,
      default: true,
    },
    lazyNodeFn: {
      type: Function,
    },
    type: {
      type: String,
      default: 'address',
    },
  },
  data() {
    return {
      transferDisabled: this.disabled,
      transferData_left: this.data_left,
      transferData_right: this.data_right,
      //左侧树选择列表
      checkedData_left: [],
      //右侧树选择列表
      checkedData_right: [],
      halfCheckedData_left: [],
      halfCheckedData_right: [],
      lazyNode: [],
      rootNode: null,
      provinceId: '',
      level: 2,
    }
  },
  watch: {
    disabled: {
      handler: function (val) {
        this.transferDisabled = val
      },
      deep: true,
    },
    data_left: {
      handler: function (val, oldVal) {
        if (val != oldVal) {
          this.transferData_left = val
        }
      },
      deep: true,
    },
    data_right: {
      handler: function (val, oldVal) {
        if (val != oldVal) {
          this.transferData_right = val
        }
      },
      deep: true,
    },
  },
  methods: {
    filterNode(ref) {
      this.$refs[ref].$refs.transferTree.filter()
    },
    getNode(ref, node) {
      return this.$refs[ref].$refs.transferTree.getNode(node)
    },
    reset() {
      this.transferData_left = _.cloneDeep(this.lazyNode)
      this.transferData_right = []
    },
    bindLeftCheckedInfoEvent: function (data) {
      this.checkedData_left = data
    },
    bindRightCheckedInfoEvent: function (data) {
      this.checkedData_right = data
    },
    bindLeftHalfCheckedInfoEvent: function (data) {
      this.halfCheckedData_left = data
    },
    bindRightHalfCheckedInfoEvent: function (data) {
      this.halfCheckedData_right = data
    },
    async loadNode(node, resolve) {
      if (this.lazyNodeFn && typeof this.lazyNodeFn === 'function') {
        return this.lazyNodeFn(node, resolve)
      }
      const getAddress = [getProvince, getCity, getDistrict]
      if (node.level > this.level) return resolve([])
      const params = node.level === 0 ? {} : { parent: node.data.id }
      let data = await getAddress[node.level](params)
      data.forEach((item) => {
        item.leaf = node.level >= this.level
        item.visible = true
      })
      if (node.level === 0) {
        this.rootNode = node
        this.rootResolve = resolve
        this.lazyNode = _.cloneDeep(data)
        this.transferData_left = _.cloneDeep(data)
      } else {
        this.handTreeData(this.transferData_left, data)
      }
      for (let node of this.transferData_right) {
        data = data.filter((item) => item.id != node.id)
      }
      return resolve(data)
    },
    handTreeData(arr, data) {
      arr.forEach((item) => {
        item.children ? this.handTreeData(item.children, data) : null
        if (item.id === data[0].parent) {
          item.children = data
        }
      })
    },
    addToLeft: function () {
      this.addToLeft_rightDataRemoveToRight()
      this.addToLeft_rightDataAddToLeft()
      this.checkedData_right = []
      this.$emit('listenRightTreeInfoEvent', this.transferData_right)
    },
    addToRight: function () {
      let allNodes = this.checkedData_left.concat(this.halfCheckedData_left)
      if (
        this.type === 'address' &&
        (allNodes.filter((item) => !this.provinceId && item.parent === 1)
          .length > 1 ||
          allNodes.filter(
            (item) =>
              this.provinceId &&
              item.id !== this.provinceId &&
              item.parent === 1
          ).length)
      ) {
        this.$message({
          type: 'success',
          showClose: true,
          message: '只能选择一个省份',
        })
        this.checkedData_left = []
        this.halfCheckedData_left = []
        this.$refs.from.$refs.transferTree.setCheckedNodes([])
        return
      }
      this.addToRight_leftDataAddToRight()
      this.addToRight_leftDataRemoveToLeft()
      this.checkedData_left = []
      this.halfCheckedData_left = []
      this.$emit('listenRightTreeInfoEvent', this.transferData_right)
    },
    addToLeft_rightDataAddToLeft: function () {
      this.type === 'address'
        ? this.handleAddressLeftAdd()
        : this.type === 'station'
        ? this.handleStationLeftAdd()
        : this.handleCommonLeftAdd()
    },
    addToLeft_rightDataRemoveToRight: function () {
      for (let node of this.checkedData_right) {
        this.transferData_right = this.transferData_right.filter(
          (item) => item.id !== node.id
        )
      }
      this.provinceId =
        !this.transferData_right.length && this.type === 'address' && ''
    },
    addToRight_leftDataAddToRight: function () {
      this.type === 'address'
        ? this.handleAddressRightAdd()
        : this.type === 'station'
        ? this.handleStationRightAdd()
        : this.handleCommonRightAdd()
    },
    addToRight_leftDataRemoveToLeft: function () {
      this.type === 'address'
        ? this.handleAddressLeftRemove()
        : this.type === 'station'
        ? this.handleStationLeftRemove()
        : this.handleCommonLeftRemove()
    },
    handleCommonLeftAdd() {
      let tmpArr = this.getArrDifSameValue(
        this.checkedData_right,
        this.transferData_left
      )
      tmpArr.forEach((item) => (item.visible = true))
      this.$nextTick(() => {
        this.filterNode('from')
      })
    },
    handleAddressLeftAdd() {
      for (let node of this.checkedData_right) {
        if (this.getNode('from', node.parent)) {
          node = this.getNode('from', node.parent)
          node.loaded = false
          node.expand()
        } else {
          this.transferData_left = _.cloneDeep(this.lazyNode)
        }
      }
    },
    handleStationLeftAdd() {
      for (let node of this.checkedData_right) {
        let indexArr = node.index.split('-')
        this.transferData_left[indexArr[0]].visible = true
        if (indexArr[1])
          this.transferData_left[indexArr[0]].children[
            indexArr[1]
          ].visible = true
        if (indexArr[2])
          this.transferData_left[indexArr[0]].children[indexArr[1]].children[
            indexArr[2]
          ].visible = true
      }
      this.$nextTick(() => {
        this.filterNode('from')
      })
    },
    handleCommonRightAdd() {
      for (let node of this.checkedData_left) {
        node.visible = true
        this.transferData_right.push(node)
      }
    },
    handleAddressRightAdd() {
      for (let node of this.checkedData_left) {
        this.transferData_right = this.transferData_right.filter(
          (item) => item.parent !== node.id && item.id !== node.id
        )
        let parentIndex = this.checkedData_left.findIndex(
          (item) => item.id === node.parent
        )
        if (parentIndex === -1) {
          let parentArr = []
          let item = this.transferFlatString(node, parentArr)
          this.transferData_right.push({
            name: item,
            id: node.id,
            parent: node.parent,
            parentArr: parentArr,
          })
        }
      }
    },
    handleStationRightAdd() {
      let stationArr = []
      for (let node of this.checkedData_left) {
        let parentIndex = this.checkedData_left.findIndex(
          (item) => item.id === node.parent
        )
        if (parentIndex === -1) {
          if (node.parent === 1) {
            node.children.forEach((city) => {
              city.children.forEach((station) => {
                if (
                  !this.transferData_right.filter(
                    (item) => item.id === station.id
                  ).length
                ) {
                  stationArr.push({
                    name: node.name + '/' + city.name + '/' + station.name,
                    id: station.id,
                    visible: true,
                    index: station.index,
                  })
                }
              })
            })
          } else if (!node.leaf) {
            let rootNode = this.getRootNode(node)
            node.children.forEach((station) => {
              if (
                !this.transferData_right.filter(
                  (item) => item.id === station.id
                ).length
              ) {
                stationArr.push({
                  name: rootNode.name + '/' + node.name + '/' + station.name,
                  id: station.id,
                  visible: true,
                  index: station.index,
                })
              }
            })
          } else {
            let rootNode = this.getRootNode(node)
            let parentNode = this.getNode('from', node.parent)
            if (
              !this.transferData_right.filter((item) => item.id === node.id)
                .length
            ) {
              stationArr.push({
                name:
                  rootNode.name + '/' + parentNode.data.name + '/' + node.name,
                id: node.id,
                visible: true,
                index: node.index,
              })
            }
          }
        }
      }
      this.transferData_right.push(...stationArr)
    },
    handleCommonLeftRemove() {
      let tmpArr = this.getArrDifSameValue(
        this.checkedData_left,
        this.transferData_left
      )
      tmpArr.forEach((item) => (item.visible = false))
      this.$nextTick(() => {
        this.filterNode('from')
      })
    },
    handleAddressLeftRemove() {
      for (let node of this.checkedData_left) {
        if (this.getNode('from', node.parent)) {
          node = this.getNode('from', node.parent)
          node.loaded = false
          node.expand()
        } else {
          this.handleChildren(this.transferData_left, node)
        }
      }
    },
    handleStationLeftRemove() {
      for (let node of this.checkedData_left) {
        let indexArr = node.index.split('-')
        this.transferData_left[indexArr[0]].visible = false
        if (indexArr[1])
          this.transferData_left[indexArr[0]].children[
            indexArr[1]
          ].visible = false
        if (indexArr[2])
          this.transferData_left[indexArr[0]].children[indexArr[1]].children[
            indexArr[2]
          ].visible = false
      }
      this.$nextTick(() => {
        this.filterNode('from')
      })
    },
    //转换成右边列表格式
    transferFlatString(node, parentArr) {
      let parentNode = this.getNode('from', node.parent)
      if (node.parent === 1) {
        this.provinceId = node.id
        return node.name
      } else if (parentNode) {
        parentArr.push(node.parent)
        return (
          this.transferFlatString(parentNode.data, parentArr) + '/' + node.name
        )
      }
    },
    getRootNode(node) {
      if (node.parent === 1) {
        return node
      } else {
        let parentNode = this.getNode('from', node.parent)
        return this.getRootNode(parentNode.data)
      }
    },
    //
    handleTrackNode(arr, node) {
      arr.forEach((item, index) => {
        item.children ? this.handleTrackNode(item.children, node) : null
        if (item.id === node.id) {
          let afterNodeData = index !== arr.length - 1 ? arr[index + 1] : null
          let beforeNodeData = index !== 0 ? arr[index - 1] : null
          beforeNodeData
            ? this.$refs.from.$refs.transferTree.insertAfter(
                item,
                beforeNodeData
              )
            : afterNodeData
            ? this.$refs.from.$refs.transferTree.insertBefore(
                item,
                afterNodeData
              )
            : this.loadNode(this.rootNode, this.rootResolve)
          this.loadNode(this.rootNode, this.rootResolve)
        }
      })
    },
    handleChildren(arr, node) {
      arr.forEach((item, index) => {
        item.id === node.id
          ? arr.splice(index, 1)
          : item.children
          ? this.handleChildren(item.children, node)
          : null
      })
    },
    arrayToTree(arr, pid) {
      var tree = []
      var temp
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].parent == pid) {
          var obj = arr[i]
          temp = this.arrayToTree(arr, arr[i].id)
          if (temp.length > 0) {
            obj.children = temp
          }
          tree.push(obj)
        }
      }
      return tree
    },

    getArrDifSameValue(arr1, arr2) {
      var result = []
      for (var i = 0; i < arr2.length; i++) {
        var obj = arr2[i]
        var id = obj.id
        var isExist = false
        for (var j = 0; j < arr1.length; j++) {
          var aj = arr1[j]
          var n = aj.id
          if (n == id) {
            isExist = true
            break
          }
        }
        if (isExist) {
          result.push(obj)
        }
      }
      return result
    },
  },
  mounted() {
    if (!this.disabled) {
      this.transferDisabled = false
    }
  },
}
</script>
<style></style>
